package org.example.service.utils.okhttp;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
public class OkHttpClients {
    private static final String TOKEN = "token";
    private static final String UC_TOKEN = "UC-Token";
    private static final String LANG = "lang";

    public static <T> OkhttpResult<T> get(OkHttpParam restParam, Class<T> tClass) throws Exception {
        String url = restParam.getApiUrl();
        if (restParam.getApiPath() != null) {
            url = url + restParam.getApiPath();
        }
        Request.Builder request = new Request.Builder();
        if (ObjectUtil.isNotEmpty(restParam.getToken())) {
            request = request
                    .addHeader(TOKEN, restParam.getToken())
            ;
        } else if (ObjectUtil.isNotEmpty(restParam.getUcToken())) {
            request = request
                    .addHeader(UC_TOKEN, restParam.getUcToken())
            ;
        } else if (StrUtil.isNotBlank(restParam.getXplugin())) {
            request = request
                    .addHeader("xplugin", restParam.getXplugin())
            ;
        }

        //2023年10月13日 因国际化在所有请求头加上lang
        if (!restParam.isUnI18N()) {
            request = addHeaderLang(request);
        }
        request = request
                .url(url)
                .get();

        return exec(restParam, request.build(), tClass);
    }

    /**
     * PUT请求json数据
     */
    public static <T> OkhttpResult<T> put(OkHttpParam restParam, String reqJsonData, Class<T> tClass) throws Exception {
        String url = restParam.getApiUrl();
        if (restParam.getApiPath() != null) {
            url = url + restParam.getApiPath();
        }
        RequestBody body = RequestBody.create(restParam.getMediaType(), reqJsonData);
        Request.Builder request = new Request.Builder();
        if (ObjectUtil.isNotEmpty(restParam.getToken())) {
            request = request
                    .addHeader("token", restParam.getToken())
            ;
        }
        //2023年10月13日 因国际化在所有请求头加上lang
        if (!restParam.isUnI18N()) {
            request = addHeaderLang(request);
        }
        request = request
                .url(url)
                .put(body);
        return exec(restParam, request.build(), tClass);

    }

    /**
     * POST请求json数据
     */
    public static <T> OkhttpResult<T> post(OkHttpParam restParam, String reqJsonData, Class<T> tClass) throws Exception {
        String url = restParam.getApiUrl();
        if (restParam.getApiPath() != null) {
            url = url + restParam.getApiPath();
        }
        RequestBody body = RequestBody.create(restParam.getMediaType(), reqJsonData);
        Request.Builder request = new Request.Builder();
        if (StrUtil.isNotBlank(restParam.getAuthorization())) {
            request = request
                    .addHeader("Authorization", restParam.getAuthorization())
            ;
        } else if (StrUtil.isNotBlank(restParam.getUcToken())) {
            request = request
                    .addHeader(UC_TOKEN, restParam.getUcToken())
            ;
        } else if (StrUtil.isNotBlank(restParam.getToken())) {
            request = request
                    .addHeader("token", restParam.getToken())
            ;
        } else if (StrUtil.isNotBlank(restParam.getFizz_appid())) {
            request = request
                    .addHeader("fizz-appid", restParam.getFizz_appid())
                    .addHeader("timestamp", restParam.getTimestamp())
                    .addHeader("sign", restParam.getSign())
            ;
        } else if (StrUtil.isNotBlank(restParam.getXplugin())) {
            request = request
                    .addHeader("xplugin", restParam.getXplugin())
            ;
        } else if (StrUtil.isNotBlank(restParam.getCoparkBaseauth())) {
            request = request
                    .addHeader("x-copark-openapi-baseauth", restParam.getCoparkBaseauth())
            ;
        }
        //2023年10月13日 因国际化在所有请求头加上lang
        if (!restParam.isUnI18N()) {
            request = addHeaderLang(request);
        }
        //url、body
        request = request
                .url(url)
                .post(body)
        ;
        log.info("[I18N]post请求头信息:{}", request.build().headers().toString());
        return exec(restParam, request.build(), tClass);

    }

    private static Request.Builder addHeaderLang(Request.Builder request) {
        try {
            request = request
                    .addHeader(LANG, "")
            ;
        } catch (Exception e) {
            log.error("获取I18nContext异常(可能异步调用)", e);
        }
        return request;
    }


    /**
     * POST请求map数据
     */
    public static <T> OkhttpResult<T> post(OkHttpParam restParam, Map<String, String> parms, Class<T> tClass) throws Exception {
        String url = restParam.getApiUrl();
        if (restParam.getApiPath() != null) {
            url = url + restParam.getApiPath();
        }
        FormBody.Builder builder = new FormBody.Builder();
        if (parms != null) {
            for (Map.Entry<String, String> entry : parms.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }
        FormBody body = builder.build();
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        return exec(restParam, request, tClass);
    }

    /**
     * 返回值封装成对象
     */
    private static <T> OkhttpResult<T> exec(
            OkHttpParam restParam,
            Request request,
            Class<T> tClass) throws Exception {
        OkhttpResult clientResult = exec(restParam, request);
        String result = clientResult.getResult();
        int status = clientResult.getStatus();
        T t = null;
        if (status == 200) {
            if (result != null && "".equalsIgnoreCase(result)) {
                t = JSON.parseObject(result, tClass);
            }
        } else {
            try {
                result = JSON.parseObject(result, String.class);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return new OkhttpResult<>(clientResult.getStatus(), result, t);
    }

    /**
     * 执行方法
     */
    private static OkhttpResult exec(
            OkHttpParam restParam,
            Request request) throws Exception {
        OkhttpResult result = null;
        OkHttpClient client = null;
        ResponseBody responseBody = null;
        try {
            client = new OkHttpClient().newBuilder()
                    .connectTimeout(restParam.getConnectTimeout(), TimeUnit.MILLISECONDS)
                    .readTimeout(restParam.getReadTimeout(), TimeUnit.MILLISECONDS)
                    .writeTimeout(restParam.getWriteTimeout(), TimeUnit.MILLISECONDS)
                    .build();
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                responseBody = response.body();
                if (responseBody != null) {
                    String responseString = responseBody.string();
                    result = new OkhttpResult<>(response.code(), responseString, null);
                }
            } else {
                throw new Exception(response.message());
            }
        } catch (Exception ex) {
            throw new Exception(ex.getMessage());
        } finally {
            if (responseBody != null) {
                responseBody.close();
            }
            if (client != null) {
                client.dispatcher().executorService().shutdown();   //清除并关闭线程池
                client.connectionPool().evictAll();                 //清除并关闭连接池
                try {
                    if (client.cache() != null) {
                        client.cache().close();                         //清除cache
                    }
                } catch (IOException e) {
                    throw new Exception(e.getMessage());
                }
            }
        }
        return result;
    }


    /**
     * POST请求soap
     * soap webservice wsdl
     *
     * @param sendMsg 请求报文
     * @param url     连接
     * @return xmlResult String类型xml
     * @throws Exception
     */
    public static String soap(String sendMsg, String url) throws Exception {
        // 开启HTTP连接ַ
        InputStreamReader isr = null;
        BufferedReader inReader = null;
        StringBuffer xmlResult;
        OutputStream outObject = null;
        try {
            URL requestUrl = new URL(url);
            HttpURLConnection httpConn = (HttpURLConnection) requestUrl.openConnection();

            // 设置HTTP请求相关信息
            httpConn.setRequestProperty("Content-Length",
                    String.valueOf(sendMsg.getBytes().length));
            httpConn.setRequestProperty("Content-Type", "application/soap+xml;charset=utf-8");
            httpConn.setRequestMethod("POST");
            httpConn.setDoOutput(true);
            httpConn.setDoInput(true);

            // 进行HTTP请求
            outObject = httpConn.getOutputStream();
            outObject.write(sendMsg.getBytes());

            if (HttpStatus.SC_OK != (httpConn.getResponseCode())) {
                throw new Exception("HTTP Request is not success, Response code is " + httpConn.getResponseCode());
            }
            // 获取HTTP响应数据
            isr = new InputStreamReader(
                    httpConn.getInputStream(), "utf-8");
            inReader = new BufferedReader(isr);
            xmlResult = new StringBuffer();
            String inputLine;
            while ((inputLine = inReader.readLine()) != null) {
                xmlResult.append(inputLine);
            }
            return xmlResult.toString();
        } catch (IOException e) {
            throw new Exception(e.getMessage());
        } finally {
            // 关闭输入流
            if (inReader != null) {
                inReader.close();
            }
            if (isr != null) {
                isr.close();
            }
            // 关闭输出流
            if (outObject != null) {
                outObject.close();
            }
        }
    }

    public static String soap2(String sendMsg, String url) throws Exception {
        // 开启HTTP连接ַ
        InputStreamReader isr = null;
        BufferedReader inReader = null;
        StringBuffer xmlResult;
        OutputStream outObject = null;
        try {
            URL requestUrl = new URL(url);
            HttpURLConnection httpConn = (HttpURLConnection) requestUrl.openConnection();

            // 设置HTTP请求相关信息
            httpConn.setRequestProperty("Content-Length",
                    String.valueOf(sendMsg.getBytes().length));
            httpConn.setRequestProperty("Content-Type", "text/xml");
            httpConn.setRequestMethod("POST");
            httpConn.setDoOutput(true);
            httpConn.setDoInput(true);

            // 进行HTTP请求
            outObject = httpConn.getOutputStream();
            outObject.write(sendMsg.getBytes());

            if (HttpStatus.SC_OK != (httpConn.getResponseCode())) {
                throw new Exception("HTTP Request is not success, Response code is " + httpConn.getResponseCode());
            }
            // 获取HTTP响应数据
            isr = new InputStreamReader(
                    httpConn.getInputStream(), "utf-8");
            inReader = new BufferedReader(isr);
            xmlResult = new StringBuffer();
            String inputLine;
            while ((inputLine = inReader.readLine()) != null) {
                xmlResult.append(inputLine);
            }
            return xmlResult.toString();
        } catch (IOException e) {
            throw new Exception(e.getMessage());
        } finally {
            // 关闭输入流
            if (inReader != null) {
                inReader.close();
            }
            if (isr != null) {
                isr.close();
            }
            // 关闭输出流
            if (outObject != null) {
                outObject.close();
            }
        }


    }

    /**
     * 使用apache的HttpClient发送http请求
     *
     * @param url     请求URL
     * @param content 请求参数
     * @return XML String
     * @Author: WgRui
     * @Date: 2020/12/16
     */
    public static String httpCilentPost(String url, String content) throws IOException {

        // 获得Http客户端
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();

        // 创建Post请求
        HttpPost httpPost = new HttpPost(url);

        // 将数据放入entity中
        StringEntity entity = new StringEntity(content, "UTF-8");
        httpPost.setEntity(entity);

        // 响应模型
        String result = null;
        CloseableHttpResponse response = null;

        try {

            //设置请求头
            //特别说明一下，此处为SOAP1.1协议
            //如果用的是SOAP1.2协议，改为："application/soap+xml;charset=UTF-8"
            httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");

            //命名空间+方法名
            //如为SOAP1.2协议不需要此项
//            httpPost.setHeader("SOAPAction", "\"http://tempuri.org/Request\"");

            // 由客户端执行(发送)Post请求
            response = httpClient.execute(httpPost);

            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();

            log.info("响应ContentType为:" + responseEntity.getContentType());
            log.info("响应状态为:" + response.getStatusLine());

            if (responseEntity != null) {
                result = EntityUtils.toString(responseEntity);
            }

        } finally {

            // 释放资源
            if (httpClient != null) {
                httpClient.close();
            }
            if (response != null) {
                response.close();
            }

        }

        return result;

    }


}
